home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 330_03 / tskque.asm < prev    next >
Assembly Source File  |  1990-10-10  |  9KB  |  345 lines

  1. ;
  2. ;    --- Version 2.2 90-10-12 10:46 ---
  3. ;
  4. ;    CTask - Queue management
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Ferrari electronic Gmbh
  9. ;        Beusselstrasse 27
  10. ;        D-1000 Berlin 21
  11. ;        Germany
  12. ;
  13. ;    Since managing the queues is one of the most timing critical 
  14. ;    parts of CTask, the main routines have been coded in Assembler.
  15. ;    The corresponding C code is included as a reference.
  16. ;
  17. ;    This file is new with 2.0.
  18. ;
  19.     name    tskque
  20. ;
  21.     include    tsk.mac
  22.     include    tskdeb.h
  23. ;
  24.     .tsk_model
  25. ;
  26.     Pubfunc    tsk_enqueue
  27.     Pubfunc    tsk_dequeue
  28.     Pubfunc    tsk_putqueue
  29.     Pubfunc    tsk_enqtimer
  30.     Pubfunc    tsk_deqtimer
  31. ;
  32.     extrn    tsk_scheduler: far
  33. ;
  34.     IF    CHECKING
  35.     CGlbext    tsk_fatal_pmd
  36.     ENDIF
  37. ;
  38.     global_ext
  39. ;
  40.     .tsk_data
  41.     .tsk_edata
  42.     .tsk_code
  43. ;
  44.     IF    CHECKING
  45. tsk_dgroup    dw    @CTASK_DATA
  46.     ENDIF
  47. ;
  48. ;
  49. ; tsk_enqueue
  50. ;
  51. ;    This routine adds a task (or any other queue element) to a queue
  52. ;    in priority order. The search starts at the queue's tail end so
  53. ;    as to better support the 'yield' operation (which disturbs the
  54. ;    priority order in the queue).
  55. ;
  56. ;void near tsk_enqueue (queheadptr q, queptr elem)
  57. ;{
  58. ;   queptr curr;
  59. ;
  60. ;   while (1)
  61. ;      {
  62. ;      curr = q->prev;
  63. ;      while (!(curr->kind & Q_HEAD) &&
  64. ;             curr->el.pri.prior < elem->el.pri.prior)
  65. ;         curr = curr->prev;
  66. ;      }
  67. ;   elem->prev = curr;
  68. ;   elem->next = curr->next;
  69. ;   curr->next = elem->next->prev = elem;
  70. ;}
  71. ;
  72. Localfunc tsk_enqueue,<uses ds di, que: far ptr, elem: far ptr>
  73. ;
  74.     CHECK_TCBPTR    elem,"tsk_enqueue: elem"
  75.     CHECK_QHEAD    que,"tsk_enqueue: queue"
  76.     les    di,elem
  77.     lds    bx,que
  78.     mov    cx,es:q_el.q_prior[di]    ; load priority into BX
  79.     lds    bx,q_prev[bx]        ; last queue element
  80. ;
  81. enq_loop:
  82.     test    q_kind[bx],Q_HEAD    ; at head?
  83.     jnz    enq_found        ; then insert
  84.     cmp    q_el.q_prior[bx],cx    ; else check priority
  85.     jae    enq_found        ; if above or equal, insert
  86. ;
  87.     lds    bx,q_prev[bx]        ; backup one element
  88.     jmp    enq_loop        ; and try again
  89. ;
  90. enq_found:
  91.     mov    word ptr es:q_prev[di],bx    ; elem->prev = curr
  92.     mov    word ptr es:q_prev+2[di],ds
  93.     mov    ax,word ptr q_next[bx]        ; elem->next = curr->next;
  94.     mov    word ptr es:q_next[di],ax
  95.     mov    dx,word ptr q_next+2[bx]
  96.     mov    word ptr es:q_next+2[di],dx
  97.     mov    word ptr q_next[bx],di        ; curr->next = elem;
  98.     mov    word ptr q_next+2[bx],es
  99.     mov    bx,ax
  100.     mov    ds,dx
  101.     mov    word ptr q_prev[bx],di        ; elem->next->prev = elem
  102.     mov    word ptr q_prev+2[bx],es
  103.     ret
  104. ;
  105. tsk_enqueue    endp
  106. ;
  107. ;
  108. ; tsk_putqueue
  109. ;
  110. ;    This routine adds a queue element to the end of a queue.
  111. ;
  112. ;void near tsk_putqueue (queheadptr q, queptr elem)
  113. ;{
  114. ;   elem->next = q;
  115. ;   elem->prev = q->prev;
  116. ;   q->prev = elem->prev->next = elem;
  117. ;}
  118. ;
  119. Localfunc tsk_putqueue,<uses ds di, que: far ptr, elem: far ptr>
  120. ;
  121.     CHECK_PTR    elem,"tsk_putqueue: elem"
  122.     CHECK_QHEAD    que,"tsk_putqueue: queue"
  123.     les    di,elem
  124.     lds    bx,que
  125.     mov    word ptr es:q_next[di],bx    ; elem->next = que
  126.     mov    word ptr es:q_next+2[di],ds
  127.     mov    ax,word ptr q_prev[bx]        ; elem->prev = que->prev;
  128.     mov    word ptr es:q_prev[di],ax
  129.     mov    dx,word ptr q_prev+2[bx]
  130.     mov    word ptr es:q_prev+2[di],dx
  131.     mov    word ptr q_prev[bx],di        ; que->prev = elem;
  132.     mov    word ptr q_prev+2[bx],es
  133.     mov    bx,ax
  134.     mov    ds,dx
  135.     mov    word ptr q_next[bx],di        ; elem->prev->next = elem
  136.     mov    word ptr q_next+2[bx],es
  137.     ret
  138. ;
  139. tsk_putqueue    endp
  140. ;
  141. ;
  142. ;
  143. ; tsk_enqtimer
  144. ;
  145. ;    This routine adds a task (or a timer element) to
  146. ;    the timeout queue.
  147. ;
  148. ;    This is slightly different from the normal enqueue in that
  149. ;    queue elements are not inserted based on priority, but rather
  150. ;    based on the tick count. Each element's tick counter stores
  151. ;    the difference in ticks to the previous element. This speeds
  152. ;    up the timeout loop, since only the first element has to be
  153. ;    counted down, but it makes insertion a tad more complicated.
  154. ;
  155. ;void near tsk_enqtimer (queptr elem, dword ticks)
  156. ;{
  157. ;   queptr curr, q;
  158. ;
  159. ;   if (!ticks)
  160. ;      return;
  161. ;   q = &GLOBDATA timer_queue;
  162. ;
  163. ;   curr = q->next;
  164. ;   while (!(curr->kind & Q_HEAD) &&
  165. ;          curr->el.ticks <= ticks)
  166. ;      {
  167. ;      ticks -= curr->el.ticks;
  168. ;      curr = curr->next;
  169. ;      if (!ticks)
  170. ;         break;
  171. ;      }
  172. ;   if (curr->kind & Q_HEAD)
  173. ;      curr->el.ticks -= ticks;
  174. ;   elem->next = curr;
  175. ;   elem->prev = curr->prev;
  176. ;   curr->prev = elem->prev->next = elem;
  177. ;   elem->el.ticks = ticks;
  178. ;}
  179. ;
  180. Localfunc tsk_enqtimer,<uses ds di, elem: far ptr, ticks: dword>
  181. ;
  182.     IFDEF    LOAD_DS
  183.     mov    ax,@CTASK_DATA
  184.     mov    ds,ax
  185.     ENDIF
  186. ;
  187.     CHECK_PTR    elem,"tsk_enqtimer: elem"
  188.     les    di,elem
  189.     IF    SINGLE_DATA
  190.     lea    bx,tsk_glob_rec.timer_queue
  191.     ELSE
  192.     lds    bx,tsk_global
  193.     add    bx,timer_queue
  194.     ENDIF
  195.     CHECK_QHEAD_R    ds,bx,"tsk_enqtimer: timer queue"
  196. ;
  197.     mov    ax,word ptr (ticks)    ; load tick count into DX:AX
  198.     mov    dx,word ptr (ticks+2)
  199.     mov    cx,ax
  200.     or    cx,dx
  201.     jz    enqt_ret
  202.     lds    bx,q_first[bx]        ; first queue element
  203. ;
  204. et_loop:
  205.     test    q_kind[bx],Q_HEAD    ; at head?
  206.     jnz    et_found1        ; then insert
  207.     sub    ax,word ptr q_el.q_ticks[bx]    ; else check ticks
  208.     sbb    dx,word ptr q_el.q_ticks+2[bx]
  209.     jc    et_found        ; insert on overflow
  210. ;
  211.     lds    bx,q_next[bx]        ; next element
  212.     jmp    et_loop            ; and try again
  213. ;
  214. et_found:
  215.     add    ax,word ptr q_el.q_ticks[bx]    ; restore ticks
  216.     adc    dx,word ptr q_el.q_ticks+2[bx]
  217. ;
  218. et_found1:
  219.     mov    word ptr es:q_el.q_ticks[di],ax    ; elem->el.ticks = ticks
  220.     mov    word ptr es:q_el.q_ticks+2[di],dx
  221. ;
  222.     test    q_kind[bx],Q_HEAD    ; at head?
  223.     jnz    et_notick        ; no tick mod if yes
  224. ;
  225.     sub    word ptr q_el.q_ticks[bx],ax    ; else curr->el.ticks -= ticks
  226.     sbb    word ptr q_el.q_ticks+2[bx],dx
  227. ;
  228. et_notick:
  229.     mov    word ptr es:q_next[di],bx    ; elem->next = curr
  230.     mov    word ptr es:q_next+2[di],ds
  231.     mov    ax,word ptr q_prev[bx]        ; elem->prev = curr->prev;
  232.     mov    word ptr es:q_prev[di],ax
  233.     mov    dx,word ptr q_prev+2[bx]
  234.     mov    word ptr es:q_prev+2[di],dx
  235.     mov    word ptr q_prev[bx],di        ; curr->prev = elem;
  236.     mov    word ptr q_prev+2[bx],es
  237.     mov    bx,ax
  238.     mov    ds,dx
  239.     mov    word ptr q_next[bx],di        ; elem->prev->next = elem
  240.     mov    word ptr q_next+2[bx],es
  241. ;
  242. enqt_ret:
  243.     ret
  244. ;
  245. tsk_enqtimer    endp
  246. ;
  247. ;
  248. ;  tsk_dequeue
  249. ;
  250. ;    This routine removes an element from a queue.
  251. ;
  252. ;void near tsk_dequeue (queptr elem)
  253. ;{
  254. ;   if (elem->next == NULL)
  255. ;      return;
  256. ;   elem->next->prev = elem->prev;
  257. ;   elem->prev->next = elem->next;
  258. ;   elem->next = NULL;
  259. ;}
  260. ;
  261. Localfunc tsk_dequeue,<uses ds di, elem: far ptr>
  262. ;
  263.     CHECK_PTR    elem,"tsk_dequeue: elem"
  264.     lds    bx,elem
  265.     les    di,q_next[bx]        ; remove from queue
  266.     mov    ax,es            ; check if enqueued
  267.     or    ax,di
  268.     jz    deq_ret            ; nothing to do if not in queue
  269.     xor    ax,ax            ; clear next pointer
  270.     mov    word ptr q_next[bx],ax
  271.     mov    word ptr q_next+2[bx],ax
  272.     lds    bx,q_prev[bx]
  273.     mov    word ptr es:q_prev[di],bx
  274.     mov    word ptr es:q_prev+2[di],ds
  275.     mov    word ptr q_next[bx],di
  276.     mov    word ptr q_next+2[bx],es
  277. ;
  278. deq_ret:
  279.     ret
  280. ;
  281. tsk_dequeue    endp
  282. ;
  283. ;
  284. ;  tsk_deqtimer
  285. ;
  286. ;    This routine removes an element from the timer queue.
  287. ;    It is different from the normal dequeue in that the tick
  288. ;    difference must be updated for the next in line.
  289. ;
  290. ;    Since this routine is also called for the timer entry in
  291. ;    task blocks when the task is made runable, we have to check
  292. ;    that the timer entry actually is enqueued in the timer queue.
  293. ;    A task could also be enqueued in the watch or hotkey queue,
  294. ;    and timer tick updating must be skipped in that case. This
  295. ;    check has been added in 2.2.
  296. ;
  297. ;void near tsk_deqtimer (queptr elem)
  298. ;{
  299. ;   if (elem->next == NULL)
  300. ;      return;
  301. ;   if (elem->kind == TYP_TIMER)
  302. ;      if (!(elem->next->kind & Q_HEAD))
  303. ;         elem->next->el.ticks += elem->el.ticks;
  304. ;   elem->next->prev = elem->prev;
  305. ;   elem->prev->next = elem->next;
  306. ;   elem->next = NULL;
  307. ;}
  308. ;
  309. Localfunc tsk_deqtimer,<uses ds di, elem: far ptr>
  310. ;
  311.     CHECK_PTR    elem,"tsk_deqtimer: elem"
  312.     lds    bx,elem
  313.     les    di,q_next[bx]
  314.     mov    ax,es
  315.     or    ax,di
  316.     jz    deqtim_ret        ; nothing to do if not in queue
  317.     cmp    q_kind[bx],TYP_TIMER    ; is it a timer element?
  318.     jne    dqt_notick        ; don't update ticks if watch/hotkey
  319.     test    es:q_kind[di],Q_HEAD
  320.     jnz    dqt_notick
  321.     mov    ax,word ptr q_el.q_ticks[bx]    ; first update next tick count
  322.     mov    dx,word ptr q_el.q_ticks+2[bx]
  323.     add    word ptr es:q_el.q_ticks[di],ax
  324.     adc    word ptr es:q_